package com.heo.util;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Stack;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class EncryptHelper
{
  public static final byte[] keys = new byte[]
  { 79, 12, 8, 82, 5, 29, 9, 5, 5, 15, 9, 21, 6, 6, 8, 8 };

  public static final int SALT_LENGTH = 5;// 加盐的长度

  private static char[] charSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();

  /**
   * 将16进制转化为62进制
   * 
   * @param number
   * @return
   */
  public static String hexConvert16To62(String number)
  {
    BigInteger rest = new BigInteger(number, 16);
    Stack<Character> stack = new Stack<Character>();
    StringBuilder result = new StringBuilder(0);
    while (rest.bitLength() != 0)
    {
      stack.add(charSet[rest.remainder(new BigInteger("62")).intValue()]);
      rest = rest.divide(new BigInteger("62"));
    }
    for (; !stack.isEmpty();)
    {
      result.append(stack.pop());
    }
    return result.toString();
  }

  /**
   * 将62进制转换成16进制数
   * 
   * @param ident62
   * @return
   */
  public static String hexConvert62To16(String sixty_str)
  {
    BigInteger multiple = new BigInteger("1");
    BigInteger result = new BigInteger("0");
    Character c;
    for (int i = 0; i < sixty_str.length(); i++)
    {
      c = sixty_str.charAt(sixty_str.length() - i - 1);
      result = result.add(multiple.multiply(BigInteger.valueOf(_62_value(c))));
      // result+=_62_value(c)*multiple;
      multiple = multiple.multiply(BigInteger.valueOf(62));
    }
    return result.toString(16);
  }

  private static int _62_value(Character c)
  {
    for (int i = 0; i < charSet.length; i++)
    {
      if (c == charSet[i])
      {
        return i;
      }
    }
    return -1;
  }

  /**
   * aes加密
   * 
   * @param sSrc
   * @return
   * @throws Exception
   */
  public static byte[] encryptForAESECB(String sSrc) throws Exception
  {
    return encryptForAESECB(sSrc, keys);
  }

  /**
   * aes加密
   * 
   * @param sSrc
   * @param keys
   * @return
   * @throws Exception
   */
  public static byte[] encryptForAESECB(String sSrc, byte[] keys) throws Exception
  {
    if (keys == null)
    {
      System.out.print("keys为空null");
      return null;
    }
    // 判断Key是否为16位
    if (keys.length != 16)
    {
      System.out.print("keys长度不是16位");
      return null;
    }
    SecretKeySpec skeySpec = new SecretKeySpec(keys, "AES");
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");// "算法/模式/补码方式"
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
    return encrypted;
    // return Base64.getEncoder().encodeToString(encrypted);//
    // 此处使用BASE64做转码功能，同时能起到2次加密的作用。
  }

  /**
   * aes加密
   * 
   * @param sSrc
   * @param sKey
   * @return
   * @throws Exception
   */
  public static byte[] encryptForAESECB(String sSrc, String sKey) throws Exception
  {
    return encryptForAESECB(sSrc, sKey.getBytes("UTF-8"));
  }

  /**
   * aes解密
   * 
   * @param sSrc
   * @return
   * @throws Exception
   */
  public static String decryptForAESECB(byte[] sSrc) throws Exception
  {
    return decryptForAESECB(sSrc, keys);
  }

  /**
   * aes解密
   * 
   * @param sSrc
   * @param keys
   * @return
   * @throws Exception
   */
  public static String decryptForAESECB(byte[] sSrc, String sKey) throws Exception
  {
    return decryptForAESECB(sSrc, sKey.getBytes("UTF-8"));
  }

  /**
   * aes解密
   * 
   * @param sSrc
   * @param keys
   * @return
   * @throws Exception
   */
  public static String decryptForAESECB(byte[] sSrc, byte[] keys) throws Exception
  {
    try
    {
      // 判断Key是否正确
      if (keys == null)
      {
        System.out.print("keys为空null");
        return null;
      }

      // 判断Key是否为16位
      if (keys.length != 16)
      {
        System.out.print("keys长度不是16位");
        return null;
      }
      SecretKeySpec skeySpec = new SecretKeySpec(keys, "AES");
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
      cipher.init(Cipher.DECRYPT_MODE, skeySpec);
      // byte[] encrypted1 = Base64.getDecoder().decode(sSrc);// 先用base64解密
      try
      {
        byte[] original = cipher.doFinal(sSrc);
        String originalString = new String(original, "utf-8");
        return originalString;
      }
      catch (Exception e)
      {
        System.out.println(e.toString());
        return null;
      }
    }
    catch (Exception ex)
    {
      System.out.println(ex.toString());
      return null;
    }
  }

  public static String getMd5(String plainText)
  {
    try
    {
      MessageDigest md = MessageDigest.getInstance("MD5");
      md.update(plainText.getBytes());
      byte b[] = md.digest();
      int i;
      StringBuffer buf = new StringBuffer("");
      for (int offset = 0; offset < b.length; offset++)
      {
        i = b[offset];
        if (i < 0) i += 256;
        if (i < 16) buf.append("0");
        buf.append(Integer.toHexString(i));
      }
      // 32位加密
      return buf.toString().toUpperCase();
    }
    catch (NoSuchAlgorithmException e)
    {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 获得62进制的md5值
   * 
   * @param encryptText
   * @return
   */
  public static String getMd5For62(String plainText)
  {
    try
    {
      String str = getMd5(plainText);
      HexHelper hHelper = new HexHelper(str, 16);
      return hHelper.HexConversion(62, 0).getMyNumber();
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 将加密后的内容以62进制输出
   * 
   * @param key
   * @return
   */
  public static String encryptEnCodeFor62(String key)
  {
    String str = encryptEnCode(key);
    return hexConvert16To62(str);
  }

  /**
   * 将原文做aes加密处理 输出16进制的内容
   * 
   * @param key
   * @return
   */
  public static String encryptEnCode(String key)
  {
    try
    {
      byte[] src = encryptForAESECB(key);// 进行aes加密
      StringBuffer sb = new StringBuffer();
      for (int i = 0; i < src.length; i++)
      {
        int v = src[i] & 0xFF;
        String hv = Integer.toHexString(v);
        if (hv.length() < 2)
        {
          sb.append(0);
        }
        sb.append(hv);
      }
      // // 再把para转换为62进制
      // HexHelper b = new HexHelper(sb.toString().toUpperCase(), 16);
      // // 加盐输出
      // String yan = RandomNumHelper.getRandomString(SALT_LENGTH);
      // return yan + b.HexConversion(62, 0).getMyNumber();// 转成62进制，小数位是0

      return sb.toString();

    }
    catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 把62进制的密文转换为原文
   * 
   * @param key
   * @return
   */
  public static String decryptEncodeFor62(String key)
  {
    String enStr = hexConvert62To16(key);
    int length = 0;
    StringBuilder temp0 = new StringBuilder();
    if (enStr.length() <= 32)
    {
      length = 32;
    }
    else if (enStr.length() <= 64)
    {
      length = 64;
    }
    else if (enStr.length() <= 96)
    {
      length = 96;
    }
    else if (enStr.length() <= 192)
    {
      length = 192;
    }
    else
    {
      length = 288;
    }
    int result_length = enStr.length();
    for (int i = 0; i < length - result_length; i++)
    {
      temp0.append('0');
    }
    return decryptEncode(temp0.toString() + enStr.toString());
  }

  /**
   * 将aes加密后的16进制密文转换为原文
   * 
   * @param key
   * @return
   */
  public static String decryptEncode(String key)
  {
    try
    {
      // 先做脱盐处理
      // key = key.substring(SALT_LENGTH);

      // 把62进制转换为16进制
      // HexHelper b2 = new HexHelper(key, 62);
      // key = b2.HexConversion(16, 0).getMyNumber();
      //
      //

      byte[] src = new byte[key.length() / 2];
      for (int i = 0; i < key.length() / 2; i++)
      {
        src[i] = (byte) Integer.parseInt(key.substring(i * 2, i * 2 + 2), 16);// 16进制转换成10进制，然后再转换成byte
      }
      // 将字节数组还原成加密串
      return decryptForAESECB(src);
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }
  }

  public static void main(String[] args)
  {
    /**
     * String xx = encryptEnCode("4085,10000"); // // System.out.println(xx); //
     * Long y = Long.parseLong("1d0ee404c7674372", 16); //
     * System.out.println(y); // // System.out.println(xx);
     * System.out.println(decryptEncodeFor62(xx)); BigInteger zz = new
     * BigInteger(xx, 16); String _62Str = _10_to_62(zz);
     * System.out.println(_62Str); String y = _62_to_10(_62Str);
     * System.out.println(y);
     **/
    //
    //

    //
    //
    //
    //
    // decryptEncode("aPTteLVhYuBT6yHtAABjYTj6Vt");

    HashSet<String> set = new HashSet<String>();
    //
    for (int i = 10000; i < 11000; i++)
    {
      System.out.println("开始计算：" + i);
      for (int j = 1; j < 10000000000l; j++)
      {
        // String source = j + "," + i;
        String source = j + "";
        try
        {
          String en = encryptEnCodeFor62(source);
          // System.out.println(source + ":" + en);
          if (j % 100000 == 0)
          {
            System.out.println(source + ":" + en);
          }
          if (set.contains(en))
          {
            System.out.println("错误，有冲突>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + en + "," + source);
          }
          set.add(en);
          // System.out.println(source + ":" + en);

          String src = decryptEncodeFor62(en);
          if (!src.equals(source))
          {
            System.out.println("错误");
          }
        }
        catch (Exception e)
        {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }

    // String xx = "总问繁体abc";
    // try
    // {
    // String yy = encryptEnCode(xx);
    // System.out.println(yy);
    // System.out.println(decryptEncode(yy));
    // }
    // catch (Exception e)
    // {
    // // TODO Auto-generated catch block
    // e.printStackTrace();
    // }

  }

}
